#include <linux/module.h>
#include <linux/init.h>
#include <linux/rbtree.h>
#include <linux/string.h>
#include <linux/slab.h>

struct dvdrb_node {
	struct rb_node node;
	char *key;
	u8 cmd;
};
struct cmd_map {
	char *key;
	u8 cmd;
}maps[] = {
	{"next", 0x1A},
	{"prev", 0x03E},
	{"stop", 0x05},
	{"play", 0x03},
	{"volumeup", 0x51},
	{"volumedown", 0x0f},
	{"subtitle", 0x50},
	{"left", 0x47},
	{"right", 0x40},
	{"ok", 0x07},
	{"up", 0x06},
	{"down", 0x44},
	{"menu", 0x4a},
	{"forward", 0x45},
	{"backward", 0x01},
	{"repeat", 0x0a},
	{"zoom", 0x14},
};

struct rb_root dvd_root = RB_ROOT;

static struct dvdrb_node * dvd_search(struct rb_root *root, const char *key)
{
	struct rb_node *node = root->rb_node;
	int ret = 0;
	struct dvdrb_node *data = NULL;
	while(node){
		data = container_of(node,struct dvdrb_node,node);
		ret = strcmp(key, data->key);
		if(ret > 0){
			node = node->rb_right;
		}else if(ret < 0){
			node = node->rb_left;
		}else {
			return node;
		}
	}
	return NULL;
}

/**
 * insert a node into rbtree 
 * @param  root tree root 
 * @param  data node to insert
 * @return  0 insert OK, 1 exists
 */
static int dvdrb_insert(struct rb_root *root, struct dvdrb_node *data)
{
	 struct rb_node **top = &(root->rb_node), *parent = NULL;
	 struct dvdrb_node *tmp = NULL;
	 int ret = 0;
	 while(*top){
	 	tmp = container_of(*top,struct dvdrb_node,node);
	 	ret = strcmp(data->key, tmp->key);
	 	parent = *top;
	 	if(ret < 0){
	 		top = &((*top)->rb_left);
	 	}else if(ret > 0){
	 		top = &((*top)->rb_right);
	 	}else {
	 		return 1;
	 	}
	 }
	 rb_link_node(&data->node, parent, top);
	 rb_insert_color(&data->node, root);
	 return 0;
}

static void traverse_internal(struct rb_node *node)
{
	struct dvdrb_node *data = NULL;
	if(node){
		data = container_of(node,struct dvdrb_node,node);
		printk("%s: %d\n", data->key, data->cmd);
		traverse_internal(node->rb_left);
		traverse_internal(node->rb_right);
	}
}

static void traverse(struct rb_root *root)
{
	if(root)
		traverse_internal(root->rb_node);
}

void dvd_rb_init(void)
{
	int i;
	struct dvdrb_node *data;
	for(i=0; i<ARRAY_SIZE(maps); i++){
		data = kzalloc(sizeof(struct dvdrb_node), GFP_KERNEL);
		if(data){
			data->key = maps[i].key;
			data->cmd = maps[i].cmd;
			dvdrb_insert(&dvd_root, data);
		}
	}
	traverse(&dvd_root);
}

u8 dvd_parse_cmd(const char *key)
{
	struct dvdrb_node * data = dvd_search(&dvd_root, key);
	return data ? (data->cmd) : 0x00;
}


static int __init test_init(void)
{

	dvd_rb_init();
	return 0;
}

static void __init test_exit(void)
{

}

module_init(test_init);
module_exit(test_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("tj<tj@163.com>");